package com.yqg.manage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.yqg.manage.common.Result;
import com.yqg.manage.controller.dto.IdentificationNumberDTO;
import com.yqg.manage.controller.dto.UserDTO;
import com.yqg.manage.controller.dto.UsernameDto;
import com.yqg.manage.entity.*;
import com.yqg.manage.exception.ServiceException;
import com.yqg.manage.mapper.*;
import com.yqg.manage.service.IUserService;
import com.yqg.manage.utils.Constants;
import com.yqg.manage.utils.JwtTokenUtil;
import com.yqg.manage.utils.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

/**
 * UserServiceImpl 服务实现类
 *
 * @author suzhuang
 * @since 2023-07-05
 */
@Service
public class UserServiceImpl extends MPJBaseServiceImpl<UserMapper, User> implements IUserService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private RoleMapper roleMapper;

    @Resource
    private UnitMapper unitMapper;

    @Resource
    private DepartmentMapper departmentMapper;

    @Resource
    private RoleMenuMapper roleMenuMapper;

    @Resource
    private MenuMapper menuMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    public UserDTO login(UserDTO userDTO) {
        // 用户密码 md5加密
        userDTO.setPassword(SecureUtil.md5(userDTO.getPassword()));
        User one = getUserInfo(userDTO);
        if (one != null) {
            BeanUtil.copyProperties(one, userDTO, true);//用于将一个对象的属性值复制到另一个对象中。
//            参数说明:
//            one: 源对象，即需要被复制属性值的对象。
//            userDTO: 目标对象，即属性值将被复制到的对象。
//            true: 布尔值参数，表示是否进行深拷贝。当为 true 时，会尝试递归地复制嵌套对象的属性值；当为 false 时，只复制对象的浅层属性值。
            // 设置token
            String token = jwtTokenUtil.generateToken(one);
            userDTO.setToken(token);
            //如果redis已经有了这个token ，就不添加
            if (!redisUtil.hasKey(token)) {
                redisUtil.set(token, one, jwtTokenUtil.getExpiration());
                //给token重设时间
                redisUtil.expire(token, Constants.EXPIRATION_TIME);
            }

            //获取当前角色id
            Long roleId = one.getUserRole();
            Role role = roleMapper.selectById(roleId);
            userDTO.setRole(role.getRoleName());
            userDTO.setRoleNo(role.getRoleNo());
            userDTO.setRoleLevel(role.getRoleLevel());

            // 获取当前角色的单位和组织
            // 单位
            LambdaQueryWrapper<Unit> unitWrapper = new LambdaQueryWrapper<>();
            unitWrapper.eq(Unit::getId, one.getUnitId());
            Unit unit = unitMapper.selectOne(unitWrapper);
            userDTO.setUnitId(unit.getId());
            userDTO.setUnitName(unit.getName());
            userDTO.setTopConfiguration(unit.getTopConfiguration());
            userDTO.setDocumentNumber(unit.getDocumentNumber());
            // 组织
            if (one.getDepartmentId() != null) {
                LambdaQueryWrapper<Department> departmentWrapper = new LambdaQueryWrapper<>();
                departmentWrapper.eq(Department::getId, one.getDepartmentId());
                Department department = departmentMapper.selectOne(departmentWrapper);
                if (department != null) {
                    userDTO.setDepartmentId(department.getId());
                    userDTO.setDepartmentName(department.getName());
                }
            }

            // 设置用户的菜单列表
            List<Menu> roleMenus = getRoleMenus(roleId, userDTO.getUnitId());
            userDTO.setMenus(roleMenus);
            userDTO.setPassword("******");
            return userDTO;
        } else {
            throw new ServiceException(Constants.CODE_4001, "用户名或密码错误");
        }
    }


    @Override
    public List<User> listAll() {
        return userMapper.selectAllUser();
    }

    /**
     * 重置密码(123456)
     */
    @Override
    public int resetPwd(int id, String password, Date date) {
        return userMapper.resetPwd(id, password, date);
    }

    @Override
    public List<UsernameDto> listAllName() {
        return userMapper.selectAllName();
    }

    @Override
    public Result allIdentificationNumber() {
        List<IdentificationNumberDTO> list = userMapper.allIdentificationNumber();
        return Result.success(list);
    }

    /**
     * 获取用户
     *
     * @param userDTO
     * @return
     */
    private User getUserInfo(UserDTO userDTO) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //登陆时由原来的username改为account
        queryWrapper.eq("account", userDTO.getAccount());//eq 方法是 MyBatis-Plus 框架中的一个查询条件构建方法，用于添加等于条件，要求属性的值与给定值相等。
        queryWrapper.eq("password", userDTO.getPassword());
        queryWrapper.eq("is_delete", "0");
        User one;
        try {
            one = getOne(queryWrapper); // 从数据库查询用户信息
        } catch (Exception e) {
            log.error("系统异常", e);
            throw new ServiceException(500, "系统错误");
        }
        return one;
    }


    /**
     * 获取当前角色的菜单列表
     *
     * @param roleId 角色ID
     * @param unitId 单位ID
     * @return 菜单列表
     */
    private List<Menu> getRoleMenus(Long roleId, Long unitId) {
        //所有菜单
        QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        List<Menu> menus = menuMapper.selectList(queryWrapper);

        if (roleId == 1) {
            // 管理员权限，所以菜单都可见
            return menus;
        } else {
            //当前用户角色菜单ID
            List<Long> roleMenus = roleMenuMapper.getDataByRoleIdAndUnitId(roleId, unitId);

            List<Menu> currentRoleMenu = new ArrayList<>();
            // 筛选当前用户角色的菜单
            for (Menu menu : menus) {
                if (roleMenus.contains(menu.getId())) {
                    currentRoleMenu.add(menu);
                }
            }
            return currentRoleMenu;
        }
    }
}
